package com.hxh.myAop;

import com.hxh.entity.Project;
import com.hxh.entity.ProjectDatasource;
import com.hxh.entity.ProjectTableFiledConfig;
import com.hxh.entity.TemplateFieldConfig;
import com.hxh.service.*;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * @author HXH
 * @description: 记录项目版本变更，记录需要操作的类型，如重启、重新生成表代码、重新初始化项目
 */
@Aspect
@Component
@Slf4j
public class ProjectConfigRecordTableFieldAspect {

    @Autowired
    private ProjectConfigRecordService projectConfigRecordService;

    @Autowired
    ProjectService projectService;

    @Autowired
    ProjectTableFiledConfigService projectTableFiledConfigService;

    @Autowired
    TemplateFieldConfigService templateFieldConfigService;
    @Autowired
    ProjectDatasourceService projectDatasourceService;

    /*************************project_table_filed_config表 标志处理 start********************************/

    /**
     * 环绕拦截 ProjectTableFiledConfigService 的 deleteById 方法
     */
    @Around("execution(* com.hxh.service.ProjectTableFiledConfigService.deleteById(..)) && args(id)")
    public Object aroundTableFiledDeleteById(ProceedingJoinPoint joinPoint, Integer id) throws Throwable {
        // 1. 执行前获取实体
        ProjectTableFiledConfig config = null;
        if (id != null) {
            config = projectTableFiledConfigService.selectById(id);
        }

        // 2. 执行原方法
        Object result = joinPoint.proceed();

        // 3. 判断是否删除成功
        boolean success = result instanceof Boolean && (Boolean) result;

        if (success && config != null) {
            processAfterTableFiledConfigChange(config);
        }
        return result;
    }

    /**
     * 拦截 ProjectTableFiledConfigService 的 insert(ProjectTableFiledConfig pojo) 方法
     */
    @AfterReturning(
            pointcut = "execution(* com.hxh.service.ProjectTableFiledConfigService.insert(com.hxh.entity.ProjectTableFiledConfig)) && args(pojo)",
            returning = "result",
            argNames = "joinPoint,result,pojo"
    )
    public void afterTableFiledInsert(JoinPoint joinPoint, boolean result, ProjectTableFiledConfig pojo) {
        if (result) {
            processAfterTableFiledConfigChange(pojo);
        }
    }

    /**
     * 环绕拦截 ProjectTableFiledConfigService 的 update 方法
     */
    @Around("execution(* com.hxh.service.ProjectTableFiledConfigService.update(com.hxh.entity.ProjectTableFiledConfig)) && args(pojo)")
    public Object aroundUpdateProjectTableFiledConfig(ProceedingJoinPoint joinPoint, ProjectTableFiledConfig pojo) throws Throwable {
        // 1. 执行前获取旧数据
        ProjectTableFiledConfig oldConfig = null;
        if (pojo.getId() != null) {
            oldConfig = projectTableFiledConfigService.selectById(pojo.getId());
        }

        // 2. 执行原方法
        Object result = joinPoint.proceed();

        // 3. 判断是否更新成功
        boolean success = result instanceof Boolean && (Boolean) result;

        if (success) {
            // 4. 对比新旧数据，判断是否需要触发重建逻辑
            if (oldConfig != null) {
                boolean hasChange = hasPropertyChanged(oldConfig, pojo,
                        "projectId", "tableName", "filedName", "showName", "showType",
                        "showRequire", "showAsTag", "showTagColor", "showInExpand",
                        "showSelectOption", "associationTable", "collectionTable");
                if (hasChange) {
                    processAfterTableFiledConfigChangeForUpdate(oldConfig, pojo);
                }
            }
        }

        return result;
    }

    private void processAfterTableFiledConfigChange(ProjectTableFiledConfig pojo) {
        Integer projectId = pojo.getProjectId();
        ProjectDatasource projectDatasource = projectDatasourceService.selectById(pojo.getDatasourceId());
        String tableName = pojo.getTableName();
        String table = projectDatasource.getMysqlDatabaseName() + "." + tableName;
        String showType = pojo.getShowType();

        Project project = projectService.selectById(projectId);
        int templateId = project.getTemplateConfig().getId();
        TemplateFieldConfig templateFieldConfig = templateFieldConfigService.getByTemplateIdAndComponentName(templateId, showType);
        if (templateFieldConfig != null && templateFieldConfig.getRebuildFlag().equals("1")) {
            projectConfigRecordService.backRebuildTables(projectId, table);
        }
        projectConfigRecordService.frontRebuildTables(projectId, table);
        projectConfigRecordService.addLocalVersion(projectId);
    }

    private void processAfterTableFiledConfigChangeForUpdate(ProjectTableFiledConfig oldOne, ProjectTableFiledConfig newOne) {
        //addLocalVersion 必+1 如果project变更，+1
        //frontRebuildTables 必+1 如果tableName或project变更，+1
        //backRebuildTables showType  showType之前是需要变更的，project变更或tableName变更或filedName变更或showType变更 +1
        //                  showType之前是需要不变更的 showType变更且需要变更 +1
        //旧的实体类
        Integer projectId = oldOne.getProjectId();
        String showType = oldOne.getShowType();
        String tableName = oldOne.getTableName();
        ProjectDatasource projectDatasource = projectDatasourceService.selectById(oldOne.getDatasourceId());
        String oldTable = projectDatasource.getMysqlDatabaseName() + "." + tableName;

        Project project = projectService.selectById(projectId);
        int templateId = project.getTemplateConfig().getId();
        TemplateFieldConfig templateFieldConfig = templateFieldConfigService.getByTemplateIdAndComponentName(templateId, showType);
        projectConfigRecordService.frontRebuildTables(projectId, oldTable);
        projectConfigRecordService.addLocalVersion(projectId);

        //新的实体类
        Integer newOneProjectId = newOne.getProjectId();
        Project newOneProject = project;
        if (!Objects.equals(projectId, newOneProjectId)) {
            newOneProject = projectService.selectById(newOneProjectId);
            projectConfigRecordService.addLocalVersion(newOneProjectId);
        }
        int newOneTemplateId = newOneProject.getTemplateConfig().getId();
        TemplateFieldConfig newOneTemplateFieldConfig = templateFieldConfig;
        String newOneShowType = newOne.getShowType();
        if (!Objects.equals(templateId, newOneTemplateId) || !Objects.equals(showType, newOneShowType)) {
            newOneTemplateFieldConfig = templateFieldConfigService.getByTemplateIdAndComponentName(newOneTemplateId, newOneShowType);
        }

        String newOneTableName = newOne.getTableName();
        ProjectDatasource projectDatasource1 = projectDatasourceService.selectById(newOne.getDatasourceId());
        String newOneTable = projectDatasource1.getMysqlDatabaseName() + "." + newOneTableName;

        boolean projectOrTableNameChange = !Objects.equals(projectId, newOneProjectId) || !Objects.equals(tableName, newOneTableName);
        if (projectOrTableNameChange) {
            projectConfigRecordService.frontRebuildTables(newOneProjectId, newOneTable);
        }
        boolean backNeedRebuild;
        if ("1".equals(templateFieldConfig.getRebuildFlag())) {
            String filedName = oldOne.getFiledName();
            backNeedRebuild = projectOrTableNameChange ||
                    !Objects.equals(filedName, newOne.getFiledName()) || !Objects.equals(showType, newOneShowType);
            if (backNeedRebuild) {
                projectConfigRecordService.backRebuildTables(projectId, oldTable);
                if (projectOrTableNameChange) {
                    projectConfigRecordService.backRebuildTables(newOneProjectId, newOneTable);
                }
            }
        } else {
            if ("1".equals(newOneTemplateFieldConfig.getRebuildFlag())) {
                projectConfigRecordService.backRebuildTables(newOneProjectId, newOneTable);
            }
        }
    }


    private static boolean hasPropertyChanged(Object oldObj, Object newObj, String... fieldNames) {
        if (oldObj == null && newObj == null) {
            return false;
        }
        if (oldObj == null || newObj == null) {
            return true;
        }
        for (String fieldName : fieldNames) {
            try {
                Field field = oldObj.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                Object oldValue = field.get(oldObj);
                Object newValue = field.get(newObj);
                if (!Objects.equals(oldValue, newValue)) {
                    return true;
                }
            } catch (Exception e) {
                log.warn("无法比较字段: {}", fieldName);
            }
        }
        return false;
    }

    /*************************project_table_filed_config表 标志处理 end********************************/

}
